package com.ywd.platform.netty.jt080.service;

import com.ywd.platform.netty.jt080.po.JT808Protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.TooLongFrameException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * JT808-帧解码器
 * <p>
 * 消息 = 标识位 + 消息头 + 消息体 + 校验码
 * <p>
 * 发送消息时：消息封装 → 计算机并填充校验码 → 转义
 * 接收消息时：转义还原 → 验证校验码 → 解析消息
 * <p>
 * 1.消息的封装：
 * 0x7e ←→ 0x7d + 0x02
 * 0x7d ←→ 0x7d + 0x01
 * 原始消息：0x30 0x7E 0x08 0x7D 0x55
 * 封装消息：0x7E 0x30 0x7D 0x02 0x08 0x7D 0x01 0x55 0x7E
 * <p>
 * 2.消息处理：
 * 基于0x7E的消息帧定界
 * 协议转义处理(0x7D -> 0x7E/0x7D)
 * 消息完整性校验
 * 分包消息重组
 */
@Slf4j
//@ChannelHandler.Sharable
//@Component
public class JT808FrameDecoder extends ByteToMessageDecoder {

    // ====================== 协议常量 ======================
    //标识位和转义
    public final static byte HEADER_FLAG = 0x7E;
    public final static byte ESCAPE_FLAG = 0x7D;
    public final static byte ESCAPE_HEADER = 0x02;
    public final static byte ESCAPE_ESCAPE = 0x01;

    // ====================== 配置参数 ======================
    public final static int MIN_FRAME_LENGTH = 12;   // 最小帧长度(12字节)
    public final static int MAX_FRAME_LENGTH = 2048; // 最大帧长度

    /**
     * 消息解码
     *
     * @param ctx 上下文，获取 Channel、Pipeline 或触发事件（如异常传递）
     * @param in  输入流
     * @param out 输出流
     */
    @Override
    public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        // 消息示例：0x7E 0x30 0x7D 0x02 0x08 0x7D 0x01 0x55 0x7E
        log.info("[帧解码器] - 收到数据,可读字节数: {}", in.readableBytes());
        // 1. 跳过非 0x7E 开头的数据（处理粘包）
        skipToHeader(in);
        // 2. 检查是否有足够的数据（至少包含头尾标识和基本头字段）
        if (in.readableBytes() < MIN_FRAME_LENGTH) {
            log.error("数据不足最小长度要求: {} < {}", in.readableBytes(), MIN_FRAME_LENGTH);
            //throw new DecoderException("数据不足最小长度要求");
            return;
        }
        // 3. 标记当前读位置
        in.markReaderIndex();
        try {
            // 4. 查找结束标识 0x7E
            int endIndex = findEndFlag(in);
            if (endIndex == -1) {
                log.error("未找到结束标识,等待更多数据");
                //throw new DecoderException("未找到结束标识，等待更多数据");
                return;
            }
            // 5. 提取完整帧
            int frameLength = endIndex - in.readerIndex() + 1;
            if (frameLength > MAX_FRAME_LENGTH) {
                in.skipBytes(frameLength);
                log.error("帧长度超出限制");
                //throw new TooLongFrameException("帧长度超出限制: " + frameLength);
                return;
            }
            ByteBuf frame = in.readRetainedSlice(frameLength);

            // 打印原始报文（十六进制格式）===================================
            log.info("原始报文: {}", ByteBufUtil.hexDump(frame));

            // 6. 反转义处理(解析)
            ByteBuf unescaped = unescape(frame);
            // 7. 验证校验码
            if (!validateChecksum(unescaped)) {
                log.error("消息校验失败");
                //throw new DecoderException("消息校验失败");
                return;
            }
            // 8. 移除头尾标识和校验码
            ByteBuf cleaned = unescaped.slice(1, unescaped.readableBytes() - 3);

            //打印解析报文================================================
            //log.info("解析报文: {}", ByteBufUtil.hexDump(cleaned));

            log.info("[帧解码器] - 成功解码消息,长度: {}", cleaned.readableBytes());
            out.add(cleaned.retain());
        } catch (Exception e) {
            // 回退到标记位置
            in.resetReaderIndex();
            log.error("[帧解码器] - 解析数据失败,错误: {}", e.getMessage());
        }
    }

    /**
     * 跳过非HEADER_FLAG开头的数据
     */
    public void skipToHeader(ByteBuf in) {
        while (in.isReadable()) {
            // 标记当前位置
            in.markReaderIndex();
            byte b = in.readByte();
            if (b == JT808Protocol.HEADER_FLAG) {
                // 找到头标识，回退到标识位置
                in.resetReaderIndex();
                return;
            }
        }
    }

    /**
     * 查找消息结束标识0x7E
     */
    public int findEndFlag(ByteBuf in) {
        int startIndex = in.readerIndex();
        int endIndex = in.writerIndex();
        // 跳过起始标识
        if (in.getByte(startIndex) != JT808Protocol.HEADER_FLAG) {
            return -1;
        }
        // 从第二个字节开始查找
        for (int i = startIndex + 1; i < endIndex; i++) {
            byte current = in.getByte(i);
            // 找到可能的结束标识
            if (current == JT808Protocol.HEADER_FLAG) {
                // 检查前一个字节是否是转义字符
                if (i > 0 && in.getByte(i - 1) == JT808Protocol.ESCAPE_FLAG) {
                    // 是转义序列的一部分，继续查找
                    continue;
                }
                return i;
            }
        }
        return -1;
    }

    /**
     * 转义还原处理(只转义)
     */
    public ByteBuf unescape(ByteBuf frame) {
        // 0x7E 0x30 0x7D 0x02 0x08 0x7D 0x01 0x55 0x7E
        // 0x7E 0x30 0x7E 0x08 0x7D 0x55 0x7E
        ByteBuf out = Unpooled.buffer(frame.readableBytes());
        boolean escaped = false;
        while (frame.isReadable()) {
            byte b = frame.readByte();
            if (escaped) {
                //0x01
                if (b == ESCAPE_ESCAPE) {
                    //0x7D
                    out.writeByte(ESCAPE_FLAG);
                    //0x02
                } else if (b == ESCAPE_HEADER) {
                    //0x7E
                    out.writeByte(HEADER_FLAG);
                } else {
                    // 非法转义序列，保留原样
                    out.writeByte(ESCAPE_FLAG);
                    out.writeByte(b);
                }
                escaped = false;
            } else {
                //0x7D
                if (b == ESCAPE_FLAG) {
                    escaped = true;
                } else {
                    out.writeByte(b);
                }
            }
        }
        // 处理未完成的转义序列
        if (escaped) {
            out.writeByte(ESCAPE_FLAG);
        }
        return out;
    }

    /**
     * 校验消息完整性（检验码）
     */
    public boolean validateChecksum(ByteBuf buf) {
        // 保存原始读索引
        int readerIndex = buf.readerIndex();
        try {
            // 跳过起始标识
            buf.skipBytes(1);
            // 计算校验范围（从消息头到消息体结束）
            // 排除起始标识和校验码
            int checkLength = buf.readableBytes() - 2;
            byte calculated = 0;
            for (int i = 0; i < checkLength; i++) {
                calculated ^= buf.getByte(buf.readerIndex() + i);
            }
            // 获取原始校验码（倒数第二字节）
            byte received = buf.getByte(buf.readerIndex() + checkLength);
            return calculated == received;
        } finally {
            // 恢复读索引
            buf.readerIndex(readerIndex);
        }
    }

    /**
     * 错误处理
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        if (cause instanceof TooLongFrameException) {
            log.error("帧过长: {}", cause.getMessage());
        } else if (cause instanceof DecoderException) {
            log.error("[帧解码器] - 解码错误: {}", cause.getMessage(), cause);
        } else {
            log.error("[帧解码器] - 解码器异常", cause);
        }
        // 传递异常给下一个处理器
        ctx.fireExceptionCaught(cause);
    }

}
